use crate::models::orders::{self, CreateParams};
use axum::{
    Json, Router,
    extract::State,
    routing::{get, post},
};
use loco_rs::prelude::*;
use serde::Deserialize;

pub fn routes() -> Router<AppContext> {
    Router::new()
        .route("/orders", post(create))
        .route("/orders/:id", get(get_by_id))
        .route("/orders/:id/status", post(update_status))
        .route("/orders/:id/delete", post(delete))
        .route("/orders/by-number/:number", get(get_by_number))
        .route("/orders/by-customer/:customer_id", get(get_by_customer))
}

async fn create(
    State(state): State<AppContext>,
    Json(params): Json<CreateParams>,
) -> Result<Response> {
    let order = orders::Model::create(&state.db, &params).await?;
    format::json(order)
}

async fn get_by_id(
    State(state): State<AppContext>,
    axum::extract::Path(id): axum::extract::Path<String>,
) -> Result<Response> {
    let order = orders::Model::find_by_id(&state.db, &id).await?;
    format::json(order)
}

async fn get_by_number(
    State(state): State<AppContext>,
    axum::extract::Path(number): axum::extract::Path<String>,
) -> Result<Response> {
    let order = orders::Model::find_by_number(&state.db, &number).await?;
    format::json(order)
}

async fn get_by_customer(
    State(state): State<AppContext>,
    axum::extract::Path(customer_id): axum::extract::Path<String>,
) -> Result<Response> {
    let orders = orders::Model::find_by_customer_id(&state.db, &customer_id).await?;
    format::json(orders)
}

#[derive(Debug, Deserialize)]
pub struct UpdateStatusParams {
    pub status: String,
}

async fn update_status(
    State(state): State<AppContext>,
    axum::extract::Path(id): axum::extract::Path<String>,
    Json(params): Json<UpdateStatusParams>,
) -> Result<Response> {
    let order = orders::Model::find_by_id(&state.db, &id).await?;
    let active_model: orders::ActiveModel = order.into();
    let updated_order = active_model.update_status(&state.db, params.status).await?;
    format::json(updated_order)
}

async fn delete(
    State(state): State<AppContext>,
    axum::extract::Path(id): axum::extract::Path<String>,
) -> Result<Response> {
    let order = orders::Model::find_by_id(&state.db, &id).await?;
    let active_model: orders::ActiveModel = order.into();
    let deleted_order = active_model.soft_delete(&state.db).await?;
    format::json(deleted_order)
}
